#include "rtxpSession.h"
#include <string.h>
#include "log.h"
#include <sys/epoll.h>
#include <random>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include "ioevent.h"
#include <sys/time.h>

static constexpr char CCH[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static std::mutex port_mutex;

#define STARTPORT 10000
#define ENDPORT 60000

static int current_port = STARTPORT;
extern int io_epfd;

static void get_port(int &port)
{
    port_mutex.lock();
    port = current_port;
	current_port+=2;
    port_mutex.unlock();
}
/*随机数*/
static string makeRandStr()
{
    string ret;
    ret.resize(10);
    std::mt19937 rng(std::random_device{}());
    for (int i = 0; i < 10; ++i)
    {
        uint32_t x = rng() % (sizeof(CCH) - 1);
        ret[i] = CCH[x];
    }
    return ret;
}

/*解析出SETUP的端口*/
static int parse_port(const char *buff, int &rtp_port, int &rtcp_port)
{

    char *p = strstr((char *)buff, "client_port=");
    if (p == NULL)
        return -1;
    p += strlen("client_port=");
    rtp_port = atoi(p);
    char *p1 = strchr(p, '-');
    if (p1 == NULL)
    {
        LOG("cant get rtcp port\n");
        return -1;
    }
    rtcp_port = atoi(p1 + 1);
    LOG("rtp port is %d and rtccccp port is %d\n", rtp_port, rtcp_port);
    return 0;
}

static string get_Date()
{
    time_t rawtime;
    struct tm *timeinfo;
    char buffer[80];

    time(&rawtime);
    timeinfo = gmtime(&rawtime);
    strftime(buffer, sizeof(buffer), "Date: %a, %d %b %Y %H:%M:%S GMT", timeinfo);

    return string(buffer);
}

static int is_num(char c)
{
    if (c >= '0' && c <= '9')
        return 1;

    return 0;
}

int RtspSession::send_rtsp_resp(int code, string status, string extra_msg)
{
    unsigned char *buffer(new unsigned char[4096]);
    snprintf((char *)buffer, sizeof(char) * 4096, "RTSP/1.0 %d %s\r\nCSeq: %s\r\n%s\r\n\
Server: %s\r\nSession:%s\r\n",
             code, status.c_str(), this->cseq.c_str(), get_Date().c_str(), SERVERNAME, sessionid.c_str());

    if (code == 200 && extra_msg.length() != 0)
    {
        snprintf((char *)buffer + strlen((char *)buffer), sizeof(char) * 4096, "%s\r\n\r\n", extra_msg.c_str());
    }
    else
    {
        snprintf((char *)buffer + strlen((char *)buffer), sizeof(char) * 4096, "\r\n");
    }

    return send_data(buffer, strlen((char *)buffer));
}

int RtspSession::create_rtp_rtcp_session(int id)
{

    struct sockaddr_in local_rtp_addr, local_rtcp_addr;
    memset(&local_rtp_addr, 0, sizeof(local_rtp_addr));
    memset(&local_rtcp_addr, 0, sizeof(local_rtcp_addr));

    local_rtcp_addr.sin_family = AF_INET;
    local_rtp_addr.sin_family = AF_INET;
    local_rtcp_addr.sin_addr.s_addr = INADDR_ANY;
    local_rtp_addr.sin_addr.s_addr = INADDR_ANY;

    int ret1 = 0, ret2 = 0;
    int rtp_fd = 0, rtcp_fd = 0;

    do
    {
        rtp_fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (rtp_fd < 0)
        {
            LOG("socket failed:%s\n", strerror(errno));
            return -1;
        }

        get_port(this->tracks[id].local_rtp_port);
        local_rtp_addr.sin_port = htons(this->tracks[id].local_rtp_port);
        this->tracks[id].local_rtcp_port = this->tracks[id].local_rtp_port + 1;

        local_rtcp_addr.sin_port = htons(this->tracks[id].local_rtcp_port);

        LOG("bind video rtp port:%d and rtccccp port %d\n", this->tracks[id].local_rtp_port, this->tracks[id].local_rtcp_port);

        if ((ret1 = bind(rtp_fd, (struct sockaddr *)&local_rtp_addr, sizeof(local_rtp_addr))) < 0)
        {
            close(rtp_fd);
            continue;
        }

        rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (rtcp_fd < 0)
        {
            LOG("socket failed:%s\n", strerror(errno));
            close(rtp_fd);
            return -1;
        }
        if ((ret2 = bind(rtcp_fd, (struct sockaddr *)&local_rtcp_addr, sizeof(local_rtcp_addr))) < 0)
        {
            close(rtcp_fd);
            close(rtp_fd);
        }

    } while (ret1 != 0 && ret2 != 0);
    if (events[rtp_fd] == nullptr)
    {
        events[rtp_fd] = new IoEvents();
    }
    events[rtp_fd]->init_events(rtp_fd, (char *)this->peer_ip.c_str(), 2, nullptr);

    if (events[rtcp_fd] == nullptr)
    {
        events[rtcp_fd] = new IoEvents();
    }

    events[rtcp_fd]->init_events(rtcp_fd, (char *)this->peer_ip.c_str(), 3, nullptr);

    ((RtpSession *)(events[rtp_fd]->session_handler))->is_video = (id == VIDEOTRACK ? true : false);
    ((RtpSession *)(events[rtp_fd]->session_handler))->rtp_header.ssrc = rtp_fd;
    ((RtpSession *)(events[rtp_fd]->session_handler))->rtcp_fd = rtcp_fd;
    ((RtpSession *)(events[rtp_fd]->session_handler))->filename = this->filename;

    ((RtcpSession *)(events[rtcp_fd]->session_handler))->rtp_fd = rtp_fd;

    this->tracks[id].rtp_fd = rtp_fd;
    this->tracks[id].rtcp_fd = rtcp_fd;
    int array[2] = {rtp_fd, rtcp_fd};

    for (int i = 0; i < 2; i++)
    {
        int fd = array[i];
        if (fd == rtp_fd) // rtp
        {
            GET(peer_port) = this->tracks[id].peer_rtp_port;
        }
        else // rtcp
        {
            GET(peer_port) = this->tracks[id].peer_rtcp_port;
        }
        GET(remote_addr).sin_family = AF_INET;
        GET(remote_addr).sin_addr.s_addr = inet_addr(GET(peer_ip).c_str()); // 接收端IP地址
        GET(remote_addr).sin_port = htons(GET(peer_port));                  // 接收端端口号
    }
    return 0;
}

/*解析rtsp信令的cseq*/
string RtspSession::getcseq(const char *data)
{
    this->cseq.clear();
    char *p = strstr((char *)data, "CSeq:");
    if (p == NULL)
        return "";

    p += strlen("CSeq:");

    while (*p != '\0' && is_num(*p) == 0)
        p++;

    while (*p != '\0' && is_num(*p) == 1)
    {
        this->cseq.append(1, *p);
        p++;
    }

    if (*p == '\0')
        return "";

    return this->cseq;
}

static std::string base64_encode(char *in_str, int in_len)
{
    std::string out;
    BIO *b64, *bio;
    BUF_MEM *bptr = NULL;
    size_t size = 0;

    if (in_str == NULL)
        return "";

    b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);

    BIO_write(bio, in_str, in_len);
    BIO_flush(bio);

    BIO_get_mem_ptr(bio, &bptr);
    out = std::string(bptr->data, bptr->length);

    BIO_free_all(bio);
    return out;
}

static int get_codec_config(unsigned char *data, int len, unsigned char type, bool is_h264, string &out)
{
    int start = 0, end = 0;
    if (len < 4)
        return -1;

    for (int i = 0; i < len; i++)
    {
        if ((is_h264 && data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 && (data[i + 3] & 0x1f) == type) ||
            (is_h264 == false && data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 && ((data[i + 3] & 0x7e) >> 1) == type))
        {
            start = i + 3;
            continue;
        }

        if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 && start != 0)
        {
            if (data[i - 1] == 0)
                end = i - 1;
            else
                end = i;
            break;
        }
    }

    if (end == 0)
        return -1;

    out = base64_encode((char *)data + start, end - start);

    if (out.length() == 0)
        return -1;

    return 0;
}

#define CHEK_CONFIG(data, len, type, is_h264, out)               \
    {                                                            \
        if (get_codec_config(data, len, type, is_h264, out) < 0) \
            return -1;                                           \
    }

static int get_sps_pps_vps(unsigned char *data, int len, string &sps, string &pps, string &vps, bool is_h264)
{

    if (len < 4 || data == NULL)
        return -1;

    if (is_h264)
    {
        CHEK_CONFIG(data, len, (unsigned char)0x07, is_h264, sps);
        CHEK_CONFIG(data, len, (unsigned char)0x08, is_h264, pps);
    }
    else
    {
        CHEK_CONFIG(data, len, (unsigned char)0x20, is_h264, vps);
        CHEK_CONFIG(data, len, (unsigned char)0x21, is_h264, sps);
        CHEK_CONFIG(data, len, (unsigned char)0x22, is_h264, pps);
    }

    return 0;
}

string RtspSession::make_sdp()
{
    int ret = this->file_parser.get_extra_data(filename);
    if (ret == -1)
    {
        send_rtsp_resp(404, "not found");
        return "";
    }
    else if (ret == -2)
    {
        send_rtsp_resp(500, "get sps error");
        return "";
    }

    char duration[32] = "";
    if (this->file_parser.is_no_seek == false) // 禁止seek
    {
        sprintf(duration, "%f", (float)file_parser.input_context->duration / AV_TIME_BASE);
    }

    char sdp[4096] = "";
    snprintf(sdp, 4096, "v=0\r\no=- 0 0 IN IP4 0.0.0.0\r\ns=Streamed by %s\r\n\
c=IN IP4 0.0.0.0\r\nt=0 0\r\na=range:npt=0-%s\r\na=control:*\r\n",
             SERVERNAME, duration);

    if (file_parser.video_index != -1)
    {
        if (get_sps_pps_vps(file_parser.first_video_extra, file_parser.first_video_extra_len, sps, pps, vps, file_parser.is_h264) < 0)
        {
            if (file_parser.first_video_extra != NULL)
                delete file_parser.first_video_extra;
            LOG("get sps failed\n");

            return "";
        }
        if (file_parser.is_h264 == true)
        {
            snprintf(sdp + strlen(sdp), sizeof(sdp) - 1, "m=video 0 RTP/AVP 96\r\na=rtpmap:96 H264/90000\r\n\
a=fmtp:96 packetization-mode=1; profile-level-id=64001E; sprop-parameter-sets=%s,%s\r\na=control:trackID=%d\r\n",
                     sps.c_str(), pps.c_str(), VIDEOTRACK);
        }
        else
        {
            snprintf(sdp + strlen(sdp), sizeof(sdp) - 1, "m=video 0 RTP/AVP 96\r\na=rtpmap:96 H265/90000\r\n\
a=fmtp:96 sprop-vps=%s; sprop-sps=%s; sprop-pps=%s\r\na=control:trackID=%d\r\n",
                     vps.c_str(), sps.c_str(), pps.c_str(), VIDEOTRACK);
        }

        if (file_parser.first_video_extra != NULL)
            delete file_parser.first_video_extra;
    }

    string aac_config;
    if (file_parser.audio_index != -1)
    {
        char buf[4] = {0};
        for (int i = 0; i < file_parser.first_audio_extra_len; i++)
        {
            snprintf(buf, sizeof(buf), "%02X", (uint8_t)file_parser.first_audio_extra[i]);
            aac_config.append(buf);
        }

        snprintf(sdp + strlen(sdp), sizeof(sdp) - 1, "m=audio 0 RTP/AVP 98\r\n\
a=rtpmap:98 mpeg4-generic/%d/%d\r\n\
a=fmtp:98 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=%s\r\n\
a=control:trackID=%d\r\n",
                 file_parser.input_context->streams[file_parser.audio_index]->codec->sample_rate,
                 file_parser.input_context->streams[file_parser.audio_index]->codec->channels, aac_config.c_str(), AUDIOTRACK);
        if (file_parser.first_audio_extra != NULL)
            delete file_parser.first_audio_extra;
    }

    this->sdp = sdp;

    return this->sdp;
}

int RtspSession::handle_options(const char *buff)
{
    char *sdp = NULL;
    char *p = strstr((char *)buff, "OPTIONS");
    if (p == NULL)
    {
        LOG("get options error\n");
        return -1;
    }

    p += strlen("OPTIONS ");
    while (*p != '\0' && *p != ' ')
    {
        this->url.append(1, *p);
        p++;
    }

    auto pos = this->url.rfind('/');
    if (pos < 0)
    {
        send_rtsp_resp(500, "invalid url");
        return -1;
    }
    this->filename = this->url.substr(pos + 1);

    LOG("filename:%s and url:%s\n", filename.c_str(), this->url.c_str());

    p = strstr((char *)buff, "\r\n\r\n");
    if (p == NULL)
    {
        LOG("get options error\n");
        return -1;
    }

    if (getcseq(buff).length() == 0)
    {
        LOG("handle_options:get seq error\n");
        return -1;
    }

    return send_rtsp_resp(200, "OK", "Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, SET_PARAMETER, GET_PARAMETER");
}

int RtspSession::read_rtsp_data()
{
    char buff[4096] = "";
    int data_len = recv_data((unsigned char *)buff, sizeof(buff));
    if (data_len < 0)
    {
        LOG("recv_data is %d\n", data_len);
        return -1;
    }
    char *p = strchr(buff, ' ');
    if (!p)
        return -1;

    string command = string((char *)buff, p - buff);

    LOG("[%s][%d][%x]read data:[%s]\n", command.c_str(), this->sock_fd, this, buff);

    auto it = func_map.find(command);
    if (it != func_map.end())
        return (this->*(it->second))(buff);

    LOG("unkown request\n");
    return -1;
}

int RtspSession::handle_describe(const char *buff)
{
    if (strstr(buff, "\r\n\r\n") == NULL)
    {
        LOG("handle_describe error\n");
        send_rtsp_resp(400, "valide");
        return -1;
    }

    if (getcseq(buff).length() == 0)
    {
        LOG("handle_describe:get cseq error\n");
        send_rtsp_resp(400, "valide");
        return -1;
    }

    this->sessionid = makeRandStr();
    make_sdp();
    string date = get_Date();
    unsigned char *buffer(new unsigned char[4096]);
    snprintf((char *)buffer, sizeof(char) * 4096 - 1, "RTSP/1.0 200 OK\r\nContent-Base: %s\r\nContent-Length: %d\r\n\
Content-Type: application/sdp\r\n\
CSeq: %s\r\n%s\r\n\
Server: %s\r\n\
Session: %s\r\nx-Accept-Dynamic-Rate: 1\r\nx-Accept-Retransmit: our-retransmit\r\n\r\n%s",
             this->url.c_str(), this->sdp.length(), this->cseq.c_str(), date.c_str(), SERVERNAME, this->sessionid.c_str(), this->sdp.c_str());

    return send_data(buffer, strlen((char *)buffer));
}

static int get_track_id(const char *buff)
{
    char *p = strstr((char *)buff, "trackID=");
    if (p == NULL)
        return -1;
    return atoi(p + strlen("trackID="));
}

int RtspSession::handle_setup(const char *buff)
{
    if (this->sessionid.length() == 0)
    {
        send_rtsp_resp(500, "no sessionid");
        return -1;
    }

    if (strstr((char *)buff, "\r\n\r\n") == NULL)
    {
        LOG("handle_setup failed:%s\n", buff);
        return -1;
    }

    int trackid = get_track_id((const char *)buff);
    if (trackid < 0 || trackid > 1)
    {
        send_rtsp_resp(500, "invalid track id");
        return -1;
    }

    if (parse_port(buff, tracks[trackid].peer_rtp_port, tracks[trackid].peer_rtcp_port) < 0)
    {
        send_rtsp_resp(500, "parse port failed");
        return -1;
    }

    if (create_rtp_rtcp_session(trackid) < 0)
    {
        send_rtsp_resp(500, "create_rtp_session");
        return -1;
    }

    unsigned char *buffer(new unsigned char[4096]);
    snprintf((char *)buffer, sizeof(char) * 4096, "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n\
Server: %s\r\n\
Session:%s\r\nTransport: RTP/AVP/UDP;unicast;client_port=%d-%d;mode=record;server_port=%d-%d;ssrc=%d\r\n\r\n",
             this->getcseq(buff).c_str(), get_Date().c_str(), SERVERNAME, sessionid.c_str(),
             this->tracks[trackid].peer_rtp_port,
             this->tracks[trackid].peer_rtcp_port,
             this->tracks[trackid].local_rtp_port,
             this->tracks[trackid].local_rtcp_port, tracks[trackid].rtp_fd);

    return send_data(buffer, strlen((char *)buffer));
}

int RtspSession::handle_teardown(const char *buff)
{

    if (this->sessionid.length() == 0)
    {
        send_rtsp_resp(500, "no sessionid");
        return -1;
    }
    this->getcseq(buff);
    send_rtsp_resp(200, "OK");
    return -1;
}

int RtspSession::handle_getpar(const char *buff)
{

    if (this->sessionid.length() == 0)
    {
        send_rtsp_resp(500, "no sessionid");
        return -1;
    }
    this->getcseq(buff);

    return send_rtsp_resp(200, "OK");
}

int RtspSession::handle_pause(const char *buff)
{

    if (this->sessionid.length() == 0)
    {
        send_rtsp_resp(500, "no sessionid");
        return -1;
    }
    if (this->tracks[VIDEOTRACK].rtp_fd != -1)
    {
        ((RtpSession *)events[this->tracks[VIDEOTRACK].rtp_fd]->session_handler)->is_pause = true;
    }
    if (this->tracks[AUDIOTRACK].rtp_fd != -1)
    {
        ((RtpSession *)events[this->tracks[AUDIOTRACK].rtp_fd]->session_handler)->is_pause = true;
    }

    this->getcseq(buff);

    return send_rtsp_resp(200, "OK");
}

static float get_start_time(const char *buff)
{
    char *p = strstr((char *)buff, "npt=");
    if (p == NULL)
    {
        return -100.00;
    }

    return atof(p + strlen("npt="));
}

static string make_rtpinfo(const string &url, Track *tracks, float start_time)
{
    char rtpinfo[1024] = "";
    snprintf(rtpinfo, sizeof(rtpinfo) - 1, "RTP-Info: ");

    int i = 0;
    do
    {
        if (i == 0 && tracks[VIDEOTRACK].rtp_fd >= 0)
        {
            int seq = ((RtpSession *)(events[tracks[VIDEOTRACK].rtp_fd]->session_handler))->rtp_header.seq;
            snprintf(rtpinfo + strlen(rtpinfo), sizeof(rtpinfo) - 1, "url=%s/trackID=%d;seq=%d;", url.c_str(), VIDEOTRACK, seq);
            if (start_time >= 0.00)
                snprintf(rtpinfo + strlen(rtpinfo), sizeof(rtpinfo) - 1, "rtptime=%f", start_time);
        }
        else if (i == 1 && tracks[AUDIOTRACK].rtp_fd >= 0)
        {
            if (tracks[AUDIOTRACK].rtp_fd >= 0)
                snprintf(rtpinfo + strlen(rtpinfo), sizeof(rtpinfo) - 1, ",");
            int seq = ((RtpSession *)(events[tracks[AUDIOTRACK].rtp_fd]->session_handler))->rtp_header.seq;
            snprintf(rtpinfo + strlen(rtpinfo), sizeof(rtpinfo) - 1, "url=%s/trackID=%d;seq=%d;", url.c_str(), AUDIOTRACK, seq);

            if (start_time >= 0.00)
                snprintf(rtpinfo + strlen(rtpinfo), sizeof(rtpinfo) - 1, "rtptime=%f", start_time);
        }
        i++;
    } while (i < 2);

    return string(rtpinfo);
}

static void init_rtp_session(int video_fd, int audio_fd)
{
    if (video_fd != -1)
    {
        RtpSession *video_session = ((RtpSession *)events[video_fd]->session_handler);
        if(events[video_session->read_timer] == nullptr)
        {
            events[video_session->read_timer] = new IoEvents();
        }
        events[video_session->read_timer]->init_events(video_session->read_timer, NULL, 0, video_session);
        video_session->start_read_timer(0, 1, 0, 201 * 1000000);
        video_session->is_pause = false;
    }
    if (audio_fd != -1)
    {
        RtpSession *audio_session = ((RtpSession *)events[audio_fd]->session_handler);
        if(events[audio_session->read_timer] == nullptr)
        {
            events[audio_session->read_timer] = new IoEvents();
        }
        events[audio_session->read_timer]->init_events(audio_session->read_timer, NULL, 0, audio_session);
        audio_session->start_read_timer(0, 1, 0, 201 * 1000000);
        audio_session->is_pause = false;
    }

    return;
}

int RtspSession::handle_play(const char *buff)
{
    float start_time = 0.00;

    if (this->sessionid.length() == 0)
    {
        send_rtsp_resp(500, "no sessionid");
        return -1;
    }

    if (start_send_media_data == false)
    {
        init_rtp_session(this->tracks[VIDEOTRACK].rtp_fd, this->tracks[AUDIOTRACK].rtp_fd);
        start_send_media_data = true;
    }
    else
    {
        start_time = get_start_time(buff);
        for (int i = 0; i < 2; i++)
        {
            if (this->tracks[i].rtp_fd != -1)
            {
                RtpSession *rtp_session = ((RtpSession *)events[this->tracks[i].rtp_fd]->session_handler);
                if (start_time - 0.00 > 0.000001)
                {
                    if (file_parser.is_no_seek == true)
                        start_time = -1.00;

                    rtp_session->start_time = start_time;
                    rtp_session->av_seek = true;
                    rtp_session->start_read_timer(0, 1, 0, 201 * 1000000);
                }
                rtp_session->is_pause = false;

                if (start_time < 0.00)
                    start_time = ntohl(rtp_session->rtp_header.timestamp) / 90000;
            }
        }
    }

    this->getcseq(buff);

    string rtpinfo = make_rtpinfo(this->url, this->tracks, start_time);
    return send_rtsp_resp(200, "OK", rtpinfo);
}

/* 获取I帧，过滤掉sps和pps*/
static int find_key_frame(unsigned char *data, int len, bool is_h264)
{
    int i = 0;
    while (i < len)
    {
        if (data[i] == (unsigned char)0x00 && data[i + 1] == (unsigned char)0x00 && (data[i + 2] == (unsigned char)0x00 || data[i + 2] == (unsigned char)0x01))
        {

            if (data[i + 2] == (unsigned char)0x00)
            {
                if (is_h264 == true)
                {
                    if (data[i + 3] == (unsigned char)0x01 && (unsigned char)(data[i + 4] & 0x1f) == (unsigned char)5)
                    {
                        return i;
                    }
                }
                else
                {
                    if (data[i + 3] == (unsigned char)0x01 && ((unsigned char)((data[i + 4] & 0x7e) >> 1) == (unsigned char)19 || (unsigned char)((data[i + 4] & 0x7e) >> 1) == (unsigned char)20))
                        return i;
                }
            }
            else if (data[i + 2] == (unsigned char)0x01)
            {
                if (is_h264)
                {
                    if ((unsigned char)(data[i + 3] & 0x1f) == (unsigned char)5)
                        return i;
                }
                else
                {

                    if ((unsigned char)((data[i + 3] & 0x7e) >> 1) == (unsigned char)19 || (unsigned char)((data[i + 3] & 0x7e) >> 1) == (unsigned char)20)
                        return i;
                }
            }
        }
        i++;
    }

    return -1;
}

/*过滤掉start code（00 00 01 or 00 00 00 01）*/
static int skip_start_code(unsigned char *data, int len)
{
    int pos = 0;
    while (pos + 4 < len && data[pos] == 0x00)
    {

        if (data[pos + 1] == 0x00 && (data[pos + 2] == 0x01 || data[pos + 2] == 0x00))
        {
            if (data[pos + 2] == 0x01)
                pos += 2;
            else
                pos += 3;
            break;
        }

        pos++;
    }
    pos++;
    return pos;
}

/*防止整型值溢出*/
static int int_value_plus(unsigned int &value, int sum)
{
    if (0xffffffff - value < sum)
    {
        value = 0;
    }
    value += sum;

    return value;
}

int RtpSession::start_read_timer(int delay, int delay_ns, int to, int to_ns)
{
    if (read_timer == -1)
        timerfd_create(CLOCK_MONOTONIC, 0);
    struct itimerspec timeout;
    timeout.it_value.tv_sec = delay;
    timeout.it_value.tv_nsec = delay_ns;
    timeout.it_interval.tv_sec = to;
    timeout.it_interval.tv_nsec = to_ns;
    timerfd_settime(this->read_timer, 0, &timeout, NULL);
    return read_timer;
}

/*单一nalu封装模式*/
int RtpSession::single_nalu(unsigned char *data, int len)
{
    unsigned char *s_data(new unsigned char[len + RTPHEADER_LEN]);
    rtp_header.seq = htons(seq++);
    if (seq == 65535)
        seq = 0;

    memcpy(s_data, &rtp_header, RTPHEADER_LEN);
    memcpy(s_data + RTPHEADER_LEN, data, len);
    send_data(s_data, len + RTPHEADER_LEN);

    int_value_plus(send_packets_count, 1);
    int_value_plus(send_bytes_count, len);
    return 0;
}

int RtpSession::fu_a_h265(unsigned char *data, int len)
{
    int pos = 0;
    bool is_first = true;
    unsigned char frame_type = (unsigned char)((data[pos] >> 1) & 0x3F);
    pos += 2;
    len -= 2;

    while (1) // FU-A封装模式
    {
        if (len <= 0)
            break;

        rtp_header.seq = htons(seq++);
        if (seq == 65535)
            seq = 0;

        unsigned char *s_data(new unsigned char[4096]);
        s_data[RTPHEADER_LEN] = (49 << 1);
        s_data[RTPHEADER_LEN] &= 0x7f;
        s_data[RTPHEADER_LEN + 1] = 1;
        s_data[RTPHEADER_LEN + 2] = frame_type;
        if (len + RTPHEADER_LEN + 3 < MTU)
        {
            rtp_header.marker = 1;
            memcpy(s_data, &rtp_header, sizeof(rtp_header));

            s_data[RTPHEADER_LEN + 2] |= 1 << 6;

            memcpy(s_data + 3 + RTPHEADER_LEN, data + pos, len);
            if (send_data(s_data, len + 3 + RTPHEADER_LEN) < 0)
                return -1;
            int_value_plus(send_packets_count, 1);
            int_value_plus(send_bytes_count, len + 3);

            break;
        }

        if (is_first)
        {
            s_data[RTPHEADER_LEN + 2] |= 1 << 7;
            is_first = false;
        }
        else
        {
            s_data[RTPHEADER_LEN + 2] &= ~(1 << 7);
        }

        memcpy(s_data, &rtp_header, sizeof(rtp_header));
        memcpy(s_data + 3 + RTPHEADER_LEN, data + pos, MTU);
        if (send_data(s_data, MTU + RTPHEADER_LEN + 3) < 0)
            return -1;
        pos += MTU;
        len -= MTU;

        int_value_plus(send_bytes_count, MTU + 3);
    }

    return 0;
}

// FU-A封装模式
int RtpSession::fu_a_h264(unsigned char *data, int len)
{
    int pos = 0;
    bool is_first = true;
    unsigned char indicator = ((data[pos] & 0x60) | 28); // fu-indicator
    unsigned char frame_type = data[pos] & 0x1f;
    pos++;
    len--;

    while (1) // FU-A封装模式
    {
        if (len <= 0)
            break;

        rtp_header.seq = htons(seq++);
        if (seq == 65535)
            seq = 0;

        unsigned char *s_data(new unsigned char[4096]);
        s_data[RTPHEADER_LEN] = indicator;
        if (len + RTPHEADER_LEN + 2 < MTU)
        {
            rtp_header.marker = 1;
            memcpy(s_data, &rtp_header, sizeof(rtp_header));

            s_data[RTPHEADER_LEN + 1] = 0x40 | frame_type;
            memcpy(s_data + 2 + RTPHEADER_LEN, data + pos, len);
            if (send_data(s_data, len + 2 + RTPHEADER_LEN) < 0)
                return -1;

            int_value_plus(send_packets_count, 1);
            int_value_plus(send_bytes_count, len + 2 + RTPHEADER_LEN);
            break;
        }

        if (is_first)
        {
            s_data[1 + RTPHEADER_LEN] = 0x80 | frame_type;
            is_first = false;
        }
        else
        {
            s_data[1 + RTPHEADER_LEN] = 0x00 | frame_type;
        }
        memcpy(s_data, &rtp_header, sizeof(rtp_header));
        memcpy(s_data + 2 + RTPHEADER_LEN, data + pos, MTU);

        if (send_data(s_data, MTU + RTPHEADER_LEN + 2) < 0)
            return -1;
        pos += MTU;
        len -= MTU;
        int_value_plus(send_bytes_count, MTU + RTPHEADER_LEN + 2);
    }

    return 0;
}

int RtpSession::video_transform_rtp(unsigned char *data, int len, int pts)
{
    if (len < 4)
        return -1;

    rtp_header.marker = 0;
    rtp_header.timestamp = htonl(pts);
    rtp_header.payload_type = 96;

    int pos = skip_start_code(data, len);

    if (len - pos + RTPHEADER_LEN < MTU) // 单一nalu封装模式
    {
        return single_nalu(data + pos, len - pos);
    }
    if (this->file_reader.is_h264)
        return fu_a_h264(data + pos, len - pos); // FU-A
    else
        return fu_a_h265(data + pos, len - pos); // FU-A
}

/*aac 采用单一nalu封包*/
int RtpSession::aac_transform_rtp(unsigned char *data, int len, int pts)
{
    rtp_header.timestamp = htonl(pts);
    rtp_header.payload_type = 98;
    rtp_header.marker = 1;
    rtp_header.seq = htons(seq++);
    if (seq == 65535)
        seq = 0;

    unsigned char *s_data(new unsigned char[4096]);

    memcpy(s_data, &rtp_header, sizeof(rtp_header));

    s_data[RTPHEADER_LEN + 0] = 0x00;
    s_data[RTPHEADER_LEN + 1] = 0x10;
    s_data[RTPHEADER_LEN + 2] = (len & 0x1FE0) >> 5;
    s_data[RTPHEADER_LEN + 3] = (len & 0x1F) << 3;
    memcpy(s_data + RTPHEADER_LEN + 4, data, len);

    if (send_data(s_data, RTPHEADER_LEN + 4 + len) < 0)
        return -1;

    int_value_plus(send_packets_count, 1);
    int_value_plus(send_bytes_count, 4 + len);
    return 0;
}

void RtpSession::clear_cache()
{
    while (packets_cache.size() != 0)
    {
        AVPacket *packet = packets_cache.front();
        if (packet)
        {
            av_packet_free(&packet);
            packets_cache.pop_front();
        }
    }

    packets_cache.clear();
}

int RtpSession::send_video(AVPacket *packet, bool is_last, int64_t start_pts)
{
    AVRational video_timebase = file_reader.input_context->streams[file_reader.video_index]->time_base;
    if (packet->flags & AV_PKT_FLAG_KEY)
    {
        int pos = find_key_frame(packet->data, packet->size, file_reader.is_h264);
        if (pos > 0)
            video_transform_rtp(packet->data + pos, packet->size - pos, packet->pts * av_q2d(video_timebase) * 90000);
    }
    else
        video_transform_rtp(packet->data, packet->size, packet->pts * av_q2d(video_timebase) * 90000);

    av_packet_free(&packet);
    packets_cache.pop_front();

    while (1)
    {
        AVPacket *next_packet = packets_cache.front();
        int64_t time_out = next_packet->pts - start_pts;
        if (time_out < 0) // maybe B frame
        {
            video_transform_rtp(next_packet->data, next_packet->size, next_packet->pts * av_q2d(video_timebase) * 90000);
            av_packet_free(&next_packet);
            packets_cache.pop_front();
        }
        else
        {
            if (is_last)
            {
                double to = (double)time_out * av_q2d(video_timebase) * 1000;
                to *= 0.97;
                this->start_read_timer(0, (int)(to * 1000000), 0, (int)(to * 1000000));
            }
            break;
        }
    }

    return 0;
}

int RtpSession::send_audio(AVPacket *packet, bool is_last, int64_t start_pts)
{
    AVRational audio_timebase = file_reader.input_context->streams[file_reader.audio_index]->time_base;
    this->aac_transform_rtp(packet->data, packet->size, (packet->pts * av_q2d(audio_timebase) * file_reader.sample_rate));
    av_packet_free(&packet);
    packets_cache.pop_front();

    while (1)
    {
        AVPacket *next_packet = packets_cache.front();
        uint64_t time_out = next_packet->pts - start_pts;
        if (time_out > 0)
        {
            if (is_last)
            {
                double to = (double)time_out * av_q2d(audio_timebase);
                if (to >= 1.000) // 扔掉错误的packet(音频转码：seek之后的第一帧偶尔有时间戳特别大的)
                {
                    av_packet_free(&next_packet);
                    packets_cache.pop_front();
                    this->start_read_timer(0, 1, 0, 1);
                    return 0;
                }
                else
                {
                    to *= 1000;
                    to *= 0.97;
                }
                this->start_read_timer(0, (int)(to * 1000000), 0, (int)(to * 1000000));
                break;
            }
        }
        else // 音频转码时，可能会出现前后pts相等的两个packet
        {
            this->aac_transform_rtp(next_packet->data, next_packet->size, (next_packet->pts * av_q2d(audio_timebase) * file_reader.sample_rate));
            av_packet_free(&next_packet);
            packets_cache.pop_front();
        }
    }

    return 0;
}

int RtpSession::read_file_data(int fd)
{
    if (this->is_pause == true || this->status == INACTIVATE)
        return 0;

    auto file_reader = &this->file_reader;

    int send_packet = 1; // 先每次发送一个包吧，否则vlc拖拽有问题(ffplay没问题)

    if (av_seek)
    {
        av_seek = false;
        if (file_reader->do_av_seek(start_time) == 0)
        {
            clear_cache();
            this->start_read_timer(0, 10 * 1000000, 1, 0); // avseek之后，重新设置timer，音视频同步
            return 0;
        }
    }

    while (packets_cache.size() < send_packet + 10) // 填满缓存
    {
        int ret = file_reader->get_avpacket(GET(filename).c_str(), &packets_cache, this->is_video ? 0 : 1, 0);
        if (ret < 0)
        {
            modify_event(io_epfd, this->read_timer, EPOLLET | EPOLLIN | EPOLLERR, EPOLL_CTL_DEL);
            clear_cache();
            return -1;
        }
    }

    int64_t start_pts;
    bool is_last = false;
    int i = 0;

    while (packets_cache.size() != 0 && i < send_packet)
    {
        AVPacket *packet = packets_cache.front();
        if (i == 0)
            start_pts = packet->pts;

        if (i == send_packet - 1 || packets_cache.size() == 1)
            is_last = true;

        if (this->is_video == false)
        {
            if (packet && packet->stream_index == file_reader->audio_index)
            {
                send_audio(packet, is_last, start_pts);
            }
        }
        else
        {
            if (packet && packet->stream_index == file_reader->video_index)
            {
                send_video(packet, is_last, start_pts);
            }
        }
        i++;
    }

    while (packets_cache.size() < send_packet + 10) // 填满缓存
    {
        int ret = file_reader->get_avpacket(GET(filename).c_str(), &packets_cache, this->is_video ? 0 : 1, 0);
        if (ret < 0)
        {
            modify_event(io_epfd, this->read_timer, EPOLLET | EPOLLIN | EPOLLERR, EPOLL_CTL_DEL);
            clear_cache();
            return -1;
        }
    }

    return 0;
}

void RtcpSession::send_sdes()
{
    auto sdes = new SDESHeader();
    sdes->ssrc = ((RtpSession *)events[this->rtp_fd]->session_handler)->rtp_header.ssrc;
    send_data((unsigned char *)sdes, sizeof(SDESHeader));

    return;
}

int RtcpSession::send_rtcp()
{
    send_sdes();
    return 0;
}

RtpSession::~RtpSession()
{
    if (read_timer != -1)
    {
        if (events[read_timer] != NULL)
        {
            delete events[read_timer];
            events[read_timer] = NULL;
        }
        close(read_timer);
    }
    clear_cache();
    return;
}
